package main

import (
	"bufio"
	"fmt"
	. "main/keil_map"
	"os"
	"strconv"
	"strings"
)

func ReadFileLineList(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

func ReadKeilMapFile(filename string) error {
	file, err := os.Open(filename)
	if err != nil {
		return err
	}

	defer file.Close()

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		line_text := scanner.Text()
		// fmt.Println(test)
		// lines = append(lines, line_text)

		g_map_reader.ReadKeilMapALineString(line_text)
		// if err != nil {
		// 	fmt.Println("Error reading line:", err)
		// }

		if g_map_reader.symbol_read_state == 2 {
			break // 结束读取
		}
	}

	if err := scanner.Err(); err != nil {
		return err
	}

	return nil
}

type TMapReader struct {
	symbol_read_state int ///< 0: 未开始, 1: 开始, 2: 结束
	symbol_list       []*TKeilImageSymbol
}

func (self *TMapReader) ReadKeilMapALineString(line string) (bool, error) {
	switch self.symbol_read_state {
	case 0:
		// 判断这一行是否包含指定内容 "Symbol Name                              Value     Ov Type        Size  Object(Section)"
		if strings.Contains(line, "Symbol Name                              Value     Ov Type        Size  Object(Section)") {
			self.symbol_read_state = 1
			return true, nil
		} else {
			return false, nil
		}
	case 1:
		// 如果是空行, 直接返回true
		if strings.TrimSpace(line) == "" {
			return true, nil
		} else if strings.Contains(line, "=================================================") {
			self.symbol_read_state = 2
			return false, nil
		}

		// 解析这一行
		symbol, err := CreateKeilImageSymbolFromString(line)
		if err != nil {
			return false, err
		}

		self.symbol_list = append(self.symbol_list, symbol)
		return true, nil
	}
	return false, nil
}

func (self *TMapReader) ReadKeilMap() ([]*TKeilImageSymbol, error) {
	if self.symbol_read_state != 2 {
		return nil, fmt.Errorf("symbol read state is not complete")
	}

	for _, symbol := range self.symbol_list {
		fmt.Println(symbol.String())
	}

	return self.symbol_list, nil
}

// ReadKeilMap 从文件中读取Keil Map信息
var g_map_reader TMapReader

func main() {
	args := os.Args
	fmt.Println("args:", args)
	fmt.Println("================== Go ===================")
	err := ReadKeilMapFile("application.map")
	if err != nil {
		fmt.Println("Error reading file:", err)
		return
	}

	// 读取完毕，输出所有符号
	// _, err = g_map_reader.ReadKeilMap()
	// if err != nil {
	// 	fmt.Println("Error reading symbols:", err)
	// 	return
	// }

	// 读取待转换的地址转换成对应的符号
	// symbol_value_dump.txt
	// 如果有传参, 则使用传入的文件名
	symbol_value_dump := "symbol_value_dump.txt"
	symbol_value_dump_result := "symbol_value_dump_result.txt"
	if len(args) > 1 {
		fmt.Println("Using input file:", args[1])
		symbol_value_dump = args[1]

		// 找到文件后缀位置, 并插入_result. 例如 symbol_value_dump.log -> symbol_value_dump_result.log
		index := strings.LastIndex(symbol_value_dump, ".")
		if index != -1 {
			symbol_value_dump_result = symbol_value_dump[:index] + "_result" + symbol_value_dump[index:]
		}

		if len(args) > 2 {
			symbol_value_dump_result = args[2]
			fmt.Println("Using output file:", symbol_value_dump_result)
		}
	} else {
		fmt.Println("Using default input file: symbol_value_dump.txt")
	}

	err = LookupKeilMapSymbol(symbol_value_dump, symbol_value_dump_result)
	if err != nil {
		fmt.Println("Error reading symbols:", err)
		return
	}

	fmt.Println("================== End ===================")
}

func LookupKeilMapSymbol(filename string, resultFile string) error {
	lines, err := ReadFileLineList(filename)
	if err != nil {
		return err
	}

	var symbols []*TKeilImageSymbol

	for _, line := range lines {
		addr, err := strconv.ParseUint(strings.TrimSpace(line), 0, 32)
		if err != nil {
			continue
		}
		addr32 := uint32(addr)
		for _, symbol := range g_map_reader.symbol_list {
			addr_start := symbol.Value
			addr_end := symbol.Value + symbol.Size
			if (addr_start <= addr32) && (addr_end > addr32) {
				symbols = append(symbols, symbol)
				// fmt.Println("Found symbol:", symbol.String())
				break
			}
		}
	}
	if len(symbols) == 0 {
		fmt.Println("Symbol not found")
		return fmt.Errorf("symbol not found")
	}

	// 将结果写入文件
	resultFileHandle, err := os.Create(resultFile)
	if err != nil {
		return err
	}
	defer resultFileHandle.Close()
	for i, symbol := range symbols {
		lines := fmt.Sprintf("%s \t>> %s\n", lines[i], symbol.String())
		resultFileHandle.WriteString(lines)
		fmt.Print(lines) // 输出到控制台
	}
	fmt.Println("\nResult written to:", resultFile)
	return nil
}
